﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace YunQue.Core.Common.TaskManager
{
    public class ProcessManager
    {
        private readonly List<Func<CancellationToken, Task>> _steps = new();
        private Func<string, Exception, Task> _errorHandler;
        private Func<int, string, Task> _progressHandler;
        private Func<string, Task> _cancelHandler;
        private string runningStepName = string.Empty;

        private ProcessManager(Func<CancellationToken, Task> firstStep)
        {
            _steps.Add(firstStep);
        }
        /// <summary>
        /// 创建第一个步骤
        /// </summary>
        public static ProcessManager RunAsync(Func<Task> step)
        {
            return new ProcessManager(async (token) =>
            {
                token.ThrowIfCancellationRequested();
                await step().ConfigureAwait(false);
            });
        }
        /// <summary>
        /// 创建第一个步骤（支持取消）
        /// </summary>
        public static ProcessManager RunAsync(Func<CancellationToken, Task> step)
        {
            return new ProcessManager(step);
        }
        /// <summary>
        /// 添加后续步骤
        /// </summary>
        public ProcessManager ThenRunAsync(Func<Task> step)
        {
            _steps.Add(async (token) =>
            {
                token.ThrowIfCancellationRequested();
                await step().ConfigureAwait(false);
            });
            return this;
        }

        /// <summary>
        /// 添加后续步骤（支持取消）
        /// </summary>
        public ProcessManager ThenRunAsync(Func<CancellationToken, Task> step)
        {
            _steps.Add(step);
            return this;
        }
        /// <summary>
        /// 注册异常处理委托
        /// </summary>
        public ProcessManager OnError(Func<string, Exception, Task> errorHandler)
        {
            _errorHandler = errorHandler;
            return this;
        }

        /// <summary>
        /// 注册进度上报委托
        /// </summary>
        public ProcessManager OnProgress(Func<int, string, Task> progressHandler)
        {
            _progressHandler = progressHandler;
            return this;
        }

        /// <summary>
        /// 注册取消处理委托
        /// </summary>
        public ProcessManager OnCancel(Func<string, Task> cancelHandler)
        {
            _cancelHandler = cancelHandler;
            return this;
        }
        /// <summary>
        /// 执行所有步骤
        /// </summary>
        public async Task ExecuteAsync(CancellationToken token = default)
        {
            // 注册统一取消回调
            using (token.Register(async () =>
            {
                if (_cancelHandler != null)
                {
                    await _cancelHandler(runningStepName).ConfigureAwait(false);
                }
            }))
            {
                int totalSteps = _steps.Count;
                for (int i = 0; i < totalSteps; i++)
                {
                    if (token.IsCancellationRequested) break;
                    runningStepName = $"步骤 {i + 1}";
                    try
                    {
                        await _steps[i](token).ConfigureAwait(false);

                        // 进度上报
                        if (_progressHandler != null)
                        {
                            int percent = (int)Math.Round(((i + 1) / (double)totalSteps) * 100);

                            await _progressHandler(percent, runningStepName).ConfigureAwait(false);
                        }
                    }
                    catch (Exception ex) when (!(ex is OperationCanceledException))
                    {
                        if (_errorHandler != null)
                        {
                            await _errorHandler(runningStepName, ex).ConfigureAwait(false);
                            if (_cancelHandler != null)
                            {
                                await _cancelHandler(runningStepName).ConfigureAwait(false);
                            }
                            break;
                        }
                        else
                        {
                            throw;
                        }
                    }
                }
            }
        }
    }
}
